package org.lex.pci.ch02.data;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Preferences {
	private static final Preferences INSTANCE = new Preferences();

	public static Preferences getInstance() {
		return INSTANCE;
	}

	/**
	 * 返回两个用户所有的对相同物品的评价
	 * 
	 * @param person1
	 * @param person2
	 * @return
	 */
	public List<Rate[]> getSharedRate(String person1, String person2) {
		List<Rate[]> commonRates = new ArrayList<Rate[]>();

		List<Rate> person1Rates = this.getRates(person1);
		List<Rate> person2Rates = this.getRates(person2);

		for (Rate person1Rate : person1Rates) {
			Rate person2Rate = Rate.findFirstByMovie(person2Rates, person1Rate.getMovie());
			if (null != person2Rate) {
				commonRates.add(new Rate[] { person1Rate, person2Rate });
			}
		}
		return commonRates;
	}

	/**
	 * 返回指定用户的所有评价
	 * 
	 * @param user
	 * @return
	 */
	public List<Rate> getRates(String user) {
		List<Rate> rateList = this.rates.get(user);
		if (null == rateList) {
			rateList = new ArrayList<Rate>();
			this.rates.put(user, rateList);
		}
		return rateList;
	}

	public Collection<String> getAllUsers() {
		return this.rates.keySet();
	}

	private Map<String, List<Rate>> rates = null;

	private Preferences() {
		rates = new HashMap<String, List<Rate>>();
		// init constants
		/*
		 * {'Lisa Rose': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5,
		 * 'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree':
		 * 2.5, 'The Night Listener': 3.0},
		 */
		this.addRate(Users.LISA_ROSE, Movies.LADY_IN_THE_WATER, 2.5);
		this.addRate(Users.LISA_ROSE, Movies.SNAKES_ON_A_PLANE, 3.5);
		this.addRate(Users.LISA_ROSE, Movies.JUST_MY_LUCK, 3.0);
		this.addRate(Users.LISA_ROSE, Movies.SUPERMAN_RETURNS, 3.5);
		this.addRate(Users.LISA_ROSE, Movies.YOU_ME_AND_DUPREE, 2.5);
		this.addRate(Users.LISA_ROSE, Movies.THE_NIGHT_LISTENER, 3.0);
		/*
		 * 'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5,
		 * 'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener':
		 * 3.0, 'You, Me and Dupree': 3.5},
		 */
		this.addRate(Users.GENE_SEYMOUR, Movies.LADY_IN_THE_WATER, 3.0);
		this.addRate(Users.GENE_SEYMOUR, Movies.SNAKES_ON_A_PLANE, 3.5);
		this.addRate(Users.GENE_SEYMOUR, Movies.JUST_MY_LUCK, 1.5);
		this.addRate(Users.GENE_SEYMOUR, Movies.SUPERMAN_RETURNS, 5.0);
		this.addRate(Users.GENE_SEYMOUR, Movies.THE_NIGHT_LISTENER, 3.0);
		this.addRate(Users.GENE_SEYMOUR, Movies.YOU_ME_AND_DUPREE, 3.5);
		/*
		 * 'Michael Phillips': {'Lady in the Water': 2.5, 'Snakes on a Plane':
		 * 3.0, 'Superman Returns': 3.5, 'The Night Listener': 4.0},
		 */
		this.addRate(Users.MICHAEL_PHILLIPS, Movies.LADY_IN_THE_WATER, 2.5);
		this.addRate(Users.MICHAEL_PHILLIPS, Movies.SNAKES_ON_A_PLANE, 3.0);
		this.addRate(Users.MICHAEL_PHILLIPS, Movies.SUPERMAN_RETURNS, 3.5);
		this.addRate(Users.MICHAEL_PHILLIPS, Movies.THE_NIGHT_LISTENER, 4.0);
		/*
		 * 'Claudia Puig': {'Snakes on a Plane': 3.5, 'Just My Luck': 3.0, 'The
		 * Night Listener': 4.5, 'Superman Returns': 4.0, 'You, Me and Dupree':
		 * 2.5},
		 */
		this.addRate(Users.CLAUDIA_PUIG, Movies.SNAKES_ON_A_PLANE, 3.5);
		this.addRate(Users.CLAUDIA_PUIG, Movies.JUST_MY_LUCK, 3.0);
		this.addRate(Users.CLAUDIA_PUIG, Movies.THE_NIGHT_LISTENER, 4.5);
		this.addRate(Users.CLAUDIA_PUIG, Movies.SUPERMAN_RETURNS, 4.0);
		this.addRate(Users.CLAUDIA_PUIG, Movies.YOU_ME_AND_DUPREE, 2.5);
		/*
		 * 'Mick LaSalle': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
		 * 'Just My Luck': 2.0, 'Superman Returns': 3.0, 'The Night Listener':
		 * 3.0, 'You, Me and Dupree': 2.0}
		 */
		this.addRate(Users.MICK_LASALLE, Movies.LADY_IN_THE_WATER, 3.0);
		this.addRate(Users.MICK_LASALLE, Movies.SNAKES_ON_A_PLANE, 4.0);
		this.addRate(Users.MICK_LASALLE, Movies.JUST_MY_LUCK, 2.0);
		this.addRate(Users.MICK_LASALLE, Movies.SUPERMAN_RETURNS, 3.0);
		this.addRate(Users.MICK_LASALLE, Movies.THE_NIGHT_LISTENER, 3.0);
		this.addRate(Users.MICK_LASALLE, Movies.YOU_ME_AND_DUPREE, 2.0);
		/*
		 * 'Jack Matthews': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
		 * 'The Night Listener': 3.0, 'Superman Returns': 5.0, 'You, Me and
		 * Dupree': 3.5},
		 */
		this.addRate(Users.JACK_MATTHEWS, Movies.LADY_IN_THE_WATER, 3.0);
		this.addRate(Users.JACK_MATTHEWS, Movies.SNAKES_ON_A_PLANE, 4.0);
		this.addRate(Users.JACK_MATTHEWS, Movies.THE_NIGHT_LISTENER, 3.0);
		this.addRate(Users.JACK_MATTHEWS, Movies.SUPERMAN_RETURNS, 5.0);
		this.addRate(Users.JACK_MATTHEWS, Movies.YOU_ME_AND_DUPREE, 3.5);
		/*
		 * 'Toby': {'Snakes on a Plane':4.5,'You, Me and Dupree':1.0,'Superman
		 * Returns':4.0}}
		 */
		this.addRate(Users.TOBY, Movies.SNAKES_ON_A_PLANE, 4.5);
		this.addRate(Users.TOBY, Movies.YOU_ME_AND_DUPREE, 1.0);
		this.addRate(Users.TOBY, Movies.SUPERMAN_RETURNS, 4.0);
	}

	private void addRate(String user, String movie, double rate) {
		this.getRates(user).add(new Rate(user, movie, rate));
	}

	public static final class Rate {
		public static Rate findFirstByMovie(Collection<Rate> c, String movie) {
			for (Rate r : c) {
				if (r.getMovie().equals(movie)) {
					return r;
				}
			}
			return null;
		}

		private String user;
		private String movie;
		private double rate;

		public Rate(String userName, String movieName, double rate) {
			super();
			this.user = userName;
			this.movie = movieName;
			this.rate = rate;
		}

		public String getUser() {
			return user;
		}

		public void setUser(String user) {
			this.user = user;
		}

		public String getMovie() {
			return movie;
		}

		public void setMovie(String movie) {
			this.movie = movie;
		}

		public double getRate() {
			return rate;
		}

		public void setRate(double rate) {
			this.rate = rate;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + ((movie == null) ? 0 : movie.hashCode());
			long temp;
			temp = Double.doubleToLongBits(rate);
			result = prime * result + (int) (temp ^ (temp >>> 32));
			result = prime * result + ((user == null) ? 0 : user.hashCode());
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			Rate other = (Rate) obj;
			if (movie == null) {
				if (other.movie != null)
					return false;
			} else if (!movie.equals(other.movie))
				return false;
			if (Double.doubleToLongBits(rate) != Double.doubleToLongBits(other.rate))
				return false;
			if (user == null) {
				if (other.user != null)
					return false;
			} else if (!user.equals(other.user))
				return false;
			return true;
		}

		@Override
		public String toString() {
			return "Rate [user=" + user + ", movie=" + movie + ", rate=" + rate + "]";
		}
	}
}
